
#include <BKeyEvent>
#include <BMouseEvent>
#include <BCamera>
#include <BViewer>
#include <BRender>
#include <BPainter>
#include <BFont>
#include <BScene>
#include <BSystem>

#include <BOrthoHandler>
#include "member_BOrthoHandler.h"

using namespace BWE;

#define member					(*(member_BOrthoHandler*)_ptr)
#define member_allocate()		_ptr = new member_BOrthoHandler(this)
#define member_release()		delete (member_BOrthoHandler*)_ptr

BOrthoHandler::BOrthoHandler()
{
	member_allocate();
}
BOrthoHandler::~BOrthoHandler()
{
	member_release();
}

void BOrthoHandler::setHome(const BVector& position, const BVector& center, const BVector& up)
{
	member.homePosition = position;
	member.homeCenter = center;
	member.homeUp = up;
}
void BOrthoHandler::home()
{
	BCamera* camera = this->camera();
	if (!camera)
		return;

	BVector position = member.homePosition;
	BVector center = member.homeCenter;
	BVector up = member.homeUp;
	BReal lensHeight = camera->lensHeight();

	if ((position - center).length() < 1e-5)
	{
		BSpace space = this->viewer()->scene()->space();
		BReal radius = space.radius();
		if (radius < 1e-5)
			radius = 1.0f;
		center = space.center();
		BReal radian = atan(lensHeight * BReal(0.5) / camera->near());
		BReal fovy = radian * 2;
		fovy *= BReal(0.5);
		fovy *= PI / 180;
		BReal dist = radius / tan(fovy);
		BVector vec(0, -1, 1);
		vec.normalize();
		position = center + vec * dist;
		up.set(0, 0, 1);
	}

	camera->setPosition(position);
	camera->setCenter(center);
	camera->setUp(up);
	this->fresh();
}

void BOrthoHandler::setMoveStep(BReal moveStep)
{
	member.moveStep = moveStep;
}
BReal BOrthoHandler::moveStep() const
{
	return member.moveStep;
}

void BOrthoHandler::setRotateStep(BReal rotateStep)
{
	member.rotateStep = rotateStep;
}
BReal BOrthoHandler::rotateStep() const
{
	return member.rotateStep;
}

void BOrthoHandler::paint(BPainter& painter)
{

}
void BOrthoHandler::render(BRender& render)
{
	//render.drawVertex(member.test0);
	//render.drawVertex(member.test1);
	//render.drawLine(member.testLine);
}

void BOrthoHandler::keyPressEvent(const BKeyEvent& keyEvent)
{
	Key key = keyEvent.key();

	BCamera* camera = this->camera();
	if (camera && key == Key_Space)
	{
		this->home();
		keyEvent.accept(true);
	}
}
void BOrthoHandler::keyReleaseEvent(const BKeyEvent& keyEvent)
{
	Key key = keyEvent.key();
}

void BOrthoHandler::mouseEnterEvent(const BMouseEvent& mouseEvent)
{
	member.rightDown = false;
	member.middleDown = false;
}
void BOrthoHandler::mouseLeaveEvent(const BMouseEvent& mouseEvent)
{
	member.rightDown = false;
	member.middleDown = false;
}

void BOrthoHandler::mousePressEvent(const BMouseEvent& mouseEvent)
{
	Button button = mouseEvent.button();
	BPoint pos = mouseEvent.pos();

	if (button == Button_Right)
	{
		member.rightDown = true;
		member.rightDownPos = pos;
		mouseEvent.accept();
	}
	if (button == Button_Middle)
	{
		member.middleDown = true;
		member.middleDownPos = pos;
		mouseEvent.accept();
	}
}
void BOrthoHandler::mouseReleaseEvent(const BMouseEvent& mouseEvent)
{
	Button button = mouseEvent.button();
	BPoint pos = mouseEvent.pos();

	if (button == Button_Right)
	{
		member.rightDown = false;
		mouseEvent.accept();
	}
	if (button == Button_Middle)
	{
		member.middleDown = false;
		mouseEvent.accept();
	}
}
void BOrthoHandler::mouseMoveEvent(const BMouseEvent& mouseEvent)
{
	if (member.rightDown && member.middleDown)
		return;

	Button button = mouseEvent.button();
	BPoint pos = mouseEvent.pos();

	if (member.middleDown && member.middleDownPos != pos)
	{
		BViewer* viewer = this->viewer();
		BCamera* camera = this->camera();
		BVector position = camera->position();
		BVector center = camera->center();
		BVector direct = center - position;
		BVector vec = -direct;
		BReal length = direct.length();

		BVector up = camera->up();
		up.normalize();

		BVector right = direct.cross(up);
		right.normalize();

		up = right.cross(direct);
		up.normalize();

		if (camera->ortho())
		{
			length = camera->near();
		}
		BVector v0 = viewer->vertex(pos, length);
		BVector v1 = viewer->vertex(member.middleDownPos, length);
		BVector offset = v1 - v0;
		camera->setPosition(position + offset);
		camera->setCenter(center + offset);
		member.middleDownPos = pos;

		member.test0 = v0;
		member.test1 = v1;
		member.testLine.set(member.test0, member.test1);
		viewer->fresh();
		mouseEvent.accept();
	}
}
void BOrthoHandler::mouseWheelEvent(const BMouseEvent& mouseEvent)
{
	BReal moveStep = this->moveStep();
	BCamera* camera = this->camera();
	int ctrlDown = mouseEvent.keyState(Key_Ctrl);
	if (camera->ortho())
	{
		BReal width = camera->lensWidth() * (1 + mouseEvent.wheel() * BReal(0.1));
		BReal height = camera->lensHeight() * (1 + mouseEvent.wheel() * BReal(0.1));
		camera->setLensWidth(width);
		camera->setLensHeight(height);
		this->fresh();
	}
	mouseEvent.accept();
}
